"""
Panel layout switcher 
Copyright (c) 2006 Peter Moberg <moberg.peter@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

On Debian systems, the complete text of the GNU General Public
License can be found in /usr/share/common-licenses/GPL file.
"""

import sys
try:
	import pygtk
	pygtk.require("2.0")
except:
	print "You need to install pyGTK or GTKv2 or set your PYTHONPATH correctly"
	sys.exit(1)

import gtk
import gtk.glade
import gtk.gdk
import layout_loader
import config
import gc


###############################################################################
import threading
class LayoutThread(threading.Thread):
	""" Thread to load layouts """
	layouts = None
	addFunction = None
	
	def run(self):
		#print "Loading profiles..."
		self.layouts = layout_loader.Layouts().load(self.addFunction)


###############################################################################
class MainWindow:
	def __init__(self):
		""" The main window """
		self.__panelListStore = gtk.ListStore(str)
		self.__layouts = layout_loader.Layouts()
		self.__widgetTree = gtk.glade.XML("panelswitcher.glade", "mainWindow")

		self.saveDialog = None

		# Auto connect signals
		dic = {"on_mainWindow_destroy" : gtk.main_quit,  
			"on_btnClose_clicked" : self.btnCloseClicked,  
			"on_btnApply_clicked" : self.btnApplyClicked,  
			"on_btnHelp_clicked" : self.btnHelpClicked,  
			"on_btnImport_clicked" : self.btnImportClicked,  
			"on_btnExport_clicked" : self.btnExportClicked  
		} 
		self.__widgetTree.signal_autoconnect(dic) 

		self.__panelList=self.__widgetTree.get_widget("tvPanelList")
		self.__panelList.set_model(self.__panelListStore)
		self.__panelList.set_headers_visible(False)
		
		tvColumn = gtk.TreeViewColumn()
		self.__panelList.append_column(tvColumn)
		cell = gtk.CellRendererText()
		tvColumn.pack_start(cell, True)
		tvColumn.add_attribute(cell, 'text', 0)
		
		# Make it searchable
		self.__panelList.set_search_column(0)
		
		# Make it sortable
		self.__panelListStore.set_sort_column_id(0,gtk.SORT_ASCENDING)

		# Connect signals
		selection = self.__panelList.get_selection()
		selection.connect('changed', self.listSelectionChanged)
		
		self.__imgPreview = self.__widgetTree.get_widget("imgPreview")
		self.__lblDescription = self.__widgetTree.get_widget("lblDescription")

		self.__widgetTree.get_widget("frameList" ).set_label(None)
		self.__widgetTree.get_widget("frameDescription").set_label(None)

		# Show the window
		self.__mainWindow = self.__widgetTree.get_widget("mainWindow")
		self.__mainWindow.show_all()
	
		t = LayoutThread()
		t.addFunction = self.addLayout
		t.start()

		try:
			self.__imageNoScreen = gtk.gdk.pixbuf_new_from_file("panelswitcher_noscreenshot.png")
			self.__imageBigLogo = gtk.gdk.pixbuf_new_from_file("panelswitcher_biglogo.png")
			self.__imgPreview.set_from_pixbuf(self.__imageBigLogo)
			self.__currentPixBuf = self.__imageBigLogo
		except:
			self.__imageNoScreen = None
		
		self.__lblDescription.set_text("This is your current profile, if you would like to store it press the button \"Create new profile\".")

		self.prevWinWidth = 640
		self.prevWinHeight = 480
		self.prevScaleWidth = 640
		self.prevScaleHeight = 480
		
		self.__imgPreview.connect('size-allocate', self.on_size_allocate)
		return


	def addLayout(self, layout):
		""" Append a layout to the list """
		gtk.threads_enter()
		self.__layouts.add(layout)
		self.__panelListStore.append([layout.name])
		gtk.threads_leave()
		return


	def btnCloseClicked(self,widget):
		gtk.main_quit()
		return


	def btnApplyClicked(self,widget):
		model, iter = self.__panelList.get_selection().get_selected()
		name = model.get_value(iter, 0)
		self.__layouts.setLayout(name)
		return
	
	def closeAbout(self, dialog, *args):
		dialog.destroy()
	
	def btnHelpClicked(self,widget):
		import config
		mainWindow = self.__widgetTree.get_widget("mainWindow")
		#mainWindow.set_sensitive(False)
		dialog = gtk.AboutDialog()
		dialog.set_name(config.name)
		dialog.set_copyright(config.copyright)
		dialog.set_license(config.license)
		dialog.set_website(config.website)
		dialog.set_authors(config.authors)
		dialog.set_artists(config.artists)
		dialog.connect("response", self.closeAbout)
		dialog.run()
		
		#mainWindow.set_sensitive(True)
		return


	def btnExportClicked(self,widget):
		# If the dialog allready is created there is no need to do it again.
		if (self.saveDialog != None):
			self.saveDialog.get_widget("saveDialog").show_all()
			return

		# Create the dialog
		else:
			self.saveDialog = gtk.glade.XML("save_dialog.glade", "saveDialog")

			# Auto connect signals
			dic = {"on_btnSave_clicked" : self.btnSave,  
				"on_bntCancel_clicked" : self.btnCancelSave,  
			} 
			self.saveDialog.signal_autoconnect(dic) 

			btnScreenshot = self.saveDialog.get_widget("checkBtnScreenshot")
			import screenshot
			screenshot = screenshot.Screenshot()
			
			if not screenshot.isPossible():
				btnScreenshot.set_sensitive(False)
				txtScreenshot = self.saveDialog.get_widget("txtScreenshot")
				txtScreenshot.set_text("To be able to include a screenshot you must have Imagemagick command line tools installed on your system. In ubuntu Imagemagick can be installed using the command: 'sudo apt-get install imagemagick'.")
		
			# Show the window
			dialog = self.saveDialog.get_widget("saveDialog")
			dialog.show_all()
		return


	def btnImportClicked(self,widget):
		dialog = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN,buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
		
		response = dialog.run()
		if response == gtk.RESPONSE_OK:
			self.copyAndLoadLayout(dialog.get_filename())
			
		#elif response == gtk.RESPONSE_CANCEL:
		#       print 'Closed, no files selected'
		
		dialog.destroy()
		return

		
	def copyAndLoadLayout(self, file):
		import shutil
		import os.path
		#try:
		shutil.copy(file, config.defaultSaveDir)
		layout = self.__layouts.append(os.path.basename(file))
		#print layout
		
		if layout != None:
			self.__panelListStore.append([layout])
		else:
			dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, message_format="Could not load layout file")
			dialog.run()
			dialog.destroy()
		return


	def listSelectionChanged(self,selection): 
		model, iter = selection.get_selected()
		if iter == None:
			return
		
		name = model.get_value(iter, 0)
		
		layout = self.__layouts.getLayout(name)
		if (layout.getPreview() != None):
			pixbuf = layout.getPreview().get_pixbuf()
			self.__currentPixBuf = pixbuf
			#self.__imgPreview.set_from_pixbuf(pixbuf)
		else:
			#print "Layout has no preview"
			#self.__imgPreview.set_from_pixbuf(None)
			self.__currentPixBuf = self.__imageNoScreen
			#self.__imgPreview.set_from_pixbuf(self.__imageNoScreen)
			
		ratio = self.__currentPixBuf.get_width() / (float)(self.__currentPixBuf.get_height())
		#print "ratio: " + str(ratio)
		height = self.prevScaleWidth / ratio
		#print "height: " + str(height)
		zoomed  = self.__currentPixBuf.scale_simple(int(self.prevScaleWidth),int(height), gtk.gdk.INTERP_BILINEAR)
		self.__imgPreview.set_from_pixbuf(zoomed)

		self.__lblDescription.set_text(layout.description)
		#print name
		return


	def btnCancelSave(self,widget):
		#print "Cancel save"
		self.saveDialog.get_widget("saveDialog").hide()
		return
		

	def btnSave(self,widget):
		mainWindow = self.__widgetTree.get_widget("mainWindow")
		screenshot = True
		#print ""
		#print "Saveing current layout to file"
		entryName = self.saveDialog.get_widget( "entryName")
		name = entryName.get_text()
		
		# Yay, this was a simple way of just getting the text... 
		txtBuffer = self.saveDialog.get_widget("textDescription").get_buffer()
		description = txtBuffer.get_text(txtBuffer.get_start_iter(), txtBuffer.get_end_iter())
		
		btnScreenshot = self.saveDialog.get_widget("checkBtnScreenshot")
		screenshot = btnScreenshot.get_active()
				
		if (name != ""):
			import layout_save
			layoutFile = layout_save.LayoutSave(name, description)
			self.saveDialog.get_widget("saveDialog").hide()


			if screenshot:
				dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK, message_format="The application will minimize it self before taking the screenshot, minimize all other applications which you do not want visible as well.")
				dialog.run()
				dialog.destroy()
				
				mainWindow.hide()
				while gtk.events_pending():
					gtk.main_iteration()
				import time
				
				time.sleep(1)
			
				# TODO: some kind of progress indicator, it can take a while to resize the image
				layoutFile.save(screenshot=screenshot, callback=self.screenshotProgress)
				#print "done"
				mainWindow.show_all()
			else:
				#print "No screenshot"
				layoutFile.save(screenshot=screenshot)
		
			iter = self.__panelListStore.append([self.__layouts.append(layoutFile.file)])
			self.__panelList.get_selection().select_iter(iter)
			
		else:
			md = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_NONE)
			md.set_markup("You must enter a name")
			md.show_all()
		
		# Clear input form
		entryName.set_text("")
		txtBuffer.set_text("")
		btnScreenshot.set_active(False)
		return


	def screenshotProgress(self, show):
		if show == True:
			pass
			#print "Compressing image..."
			
			
	def on_size_allocate(self, img, allocation, *args):
		
		if allocation.width != self.prevWinWidth or allocation.height != self.prevWinHeight:
			window_height = allocation.height
			window_width = allocation.width
			pixbuf = img.get_pixbuf()
			
			## Maintain aspect ratio:
			w_height = (window_width * pixbuf.get_height()) / pixbuf.get_width()
			h_width = (window_height * pixbuf.get_width()) / pixbuf.get_height()
			w_height_diff = window_height - w_height
			h_width_diff = window_width - h_width
		
			if w_height_diff >= 0 and h_width_diff >= 0:
				#Both are would be smaller than the window pick the bigger one
				if w_height_diff < h_width_diff:
					width = window_width
					height = w_height
				else:
					height = window_height
					width = h_width
				
			elif w_height_diff < 0:
				# height is going to touch the window edge sooner
				# size based on height
				height = window_height
				width = h_width
				
		
			else:
				# width is going to touch the window edge sooner
				# size based on width 
				width = window_width
				height = w_height
		
	
			if height > self.__currentPixBuf.get_height():
				height = self.__currentPixBuf.get_height()
			
			if width > self.__currentPixBuf.get_width():
				width = self.__currentPixBuf.get_width()
		
			if (width, height) != (pixbuf.get_width(), pixbuf.get_height()):
				# Use the original pixbuf
				del pixbuf
				pixbuf_zoomed = self.__currentPixBuf.scale_simple(int(width),int(height), gtk.gdk.INTERP_BILINEAR)
				img.set_from_pixbuf(pixbuf_zoomed)
				self.prevScaleWidth = width
				self.prevScaleHeight = height
				
				# If we do not garbage collect, the zooming can easily eat a LOT of memory. 
				gc.collect()
				
				
				
		self.prevWinWidth = allocation.width
		self.prevWinHeight = allocation.height
		return
		


###############################################################################

# Main function
#LayoutThread().start()
#gtk.threads_init()
gtk.gdk.threads_init()
app=MainWindow()
gtk.main()
